`define HLT 3'b000
`define SKZ 3'b001
`define ADD 3'b010
`define AND 3'b011
`define XOR 3'b100
`define LDA 3'b101
`define STO 3'b110
`define JMP 3'b111

module control #(
    parameter PERI0 = 3'b000,
    parameter PERI1 = 3'b001,
    parameter PERI2 = 3'b010,
    parameter PERI3 = 3'b011,
    parameter PERI4 = 3'b100,
    parameter PERI5 = 3'b101,
    parameter PERI6 = 3'b110,
    parameter PERI7 = 3'b111
) (
    output reg rd, wr, ld_ir, ld_ac,
    ld_pc, inc_pc, halt, data_e, sel,
    input [2 : 0] opcode,
    input zero, clk, rst_
);
    reg [2:0] nexstate;
    reg [2:0] state;
    always @(posedge clk or negedge rst_) begin
        if (!rst_) begin
            state <= PERI0;
        end else begin
            state <= nexstate;
        end
    end
    always @(state) begin
        case (state)
            PERI0: nexstate <= PERI1;
            PERI1: nexstate <= PERI2;
            PERI2: nexstate <= PERI3;
            PERI3: nexstate <= PERI4;
            PERI4: nexstate <= PERI5;
            PERI5: nexstate <= PERI6;
            PERI6: nexstate <= PERI7;
            PERI7: nexstate <= PERI0;
            default: nexstate <= PERI1;
        endcase
    end
    always @(opcode or state or zero) begin: blk
        reg alu_op;
        alu_op = (opcode==`ADD||opcode==`AND||opcode==`XOR||opcode==`LDA);
        case (state)
            PERI0: begin
                sel =      0;
                rd =  alu_op;
                ld_ir =    0;
                inc_pc =   (opcode==`SKZ)&zero|(opcode==`JMP);
                halt =     0;
                ld_pc =    (opcode==`JMP);
                data_e = !alu_op;
                ld_ac = alu_op;
                wr =       (opcode==`STO);
            end
            PERI1: begin
                sel =      1;
                rd =       0;
                ld_ir =    0;
                inc_pc =   0;
                halt =     0;
                ld_pc =    0;
                data_e =   0;
                ld_ac =    0;
                wr =       0;
            end
            PERI2: begin
                sel =      1;
                rd =       1;
                ld_ir =    0;
                inc_pc =   0;
                halt =     0;
                ld_pc =    0;
                data_e =   0;
                ld_ac =    0;
                wr =       0;
            end
            PERI3: begin
                sel =      1;
                rd =       1;
                ld_ir =    1;
                inc_pc =   0;
                halt =     0;
                ld_pc =    0;
                data_e =   0;
                ld_ac =    0;
                wr =       0;
            end
            PERI4: begin
                sel =      1;
                rd =       1;
                ld_ir =    1;
                inc_pc =   0;
                halt =     0;
                ld_pc =    0;
                data_e =   0;
                ld_ac =    0;
                wr =       0;
            end
            PERI5: begin
                sel =      0;
                rd =       0;
                ld_ir =    0;
                inc_pc =   1;
                halt = (opcode==`HLT);
                ld_pc =    0;
                data_e =   0;
                ld_ac =    0;
                wr =       0;
            end
            PERI6: begin
                sel =      0;
                rd =  alu_op;
                ld_ir =    0;
                inc_pc =   0;
                halt =     0;
                ld_pc =    0;
                data_e =   0;
                ld_ac =    0;
                wr =       0;
            end
            PERI7: begin
                sel =      0;
                rd =  alu_op;
                ld_ir =    0;
                inc_pc = (opcode==`SKZ)&zero;
                halt =     0;
                ld_pc = (opcode==`JMP);
                data_e = !alu_op;
                ld_ac =    0;
                wr =       0;
            end
            default: begin
                sel =      1;
                rd =       0;
                ld_ir =    0;
                inc_pc =   0;
                halt =     0;
                ld_pc =    0;
                data_e =   0;
                ld_ac =    0;
                wr =       0;
            end
        endcase
    end
endmodule